package com.easylinkin.linkappapi.gaodemap.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.easylinkin.linkappapi.gaodemap.entity.*;
import com.easylinkin.linkappapi.gaodemap.service.GaoDeApiService;
import com.easylinkin.linkappapi.gaodemap.util.ConvertLocationTask;
import com.easylinkin.linkappapi.gaodemap.util.GaodeUtils;
import com.easylinkin.linkappapi.gaodemap.util.GeoFenceUtil;
import com.easylinkin.linkappapi.gaodemap.util.InverseCodingTask;
import com.easylinkin.linkappapi.openapi.util.HttpClientUtil;
import jodd.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.HttpGet;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * class info :高德地图API接口服务实现
 *
 * @author liuqihang
 * @date 2021/6/24 11:06
 */
@Service
@Slf4j
public class GaoDeApiServiceImpl implements GaoDeApiService {

    @Value("${gaode.api.key}")
    public String key;

    @Value("${gaode.api.wep_api_url}")
    public String wepApiUrl;

    @Value("${gaode.api.location_convert_url}")
    public String locationConvertUrl;

    @Value("${gaode.api.sid}")
    public String sid;

    @Value("${gaode.api.track_location_url}")
    public String trackLocationUrl;
    @Value("${gaode.api.fenceUrl:https://tsapi.amap.com/v1/track/geofence}")
    public String fenceUrl;

    @Override
    public Map<String, String> getGeographyInverseCoding(List<InverseCodingParams> parameters) throws ExecutionException, InterruptedException {
        Map<String, String> result = new LinkedHashMap<>();
        if(parameters == null || parameters.isEmpty()){
            return result;
        }
        List<String> locationList = parameters.stream().map(InverseCodingParams::getLocation).collect(Collectors.toList());

        int size = locationList.size();
        int baseNum = 20;
        /**将集合切分的段数**/
        int sunSum = GaodeUtils.getLoopCount(size, baseNum);
        int listStart,listEnd;

        //存储线程的返回值
        List<Future<Map<String, String>>> singleResult = new LinkedList<Future<Map<String, String>>>();
        ExecutorService executorService;
        ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").get();
        executorService = new ThreadPoolExecutor(50, 100,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>(4096), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());

        for (int i = 1; i <= sunSum; i++) {
            listStart = (i-1)*baseNum;
            listEnd = listStart + baseNum;
            if(i == sunSum){
                listEnd = size;
            }
            List<String> sunList = locationList.subList(listStart,listEnd);
            StringBuilder locationAppend = new StringBuilder();
            for (String location:
                    sunList) {
                locationAppend.append("|").append(location);
            }
            String reqLocation = locationAppend.toString();
            reqLocation = reqLocation.substring(1);

            InverseCodingTask inverseCodingTask = new InverseCodingTask(reqLocation, true, key, wepApiUrl);
            Future<Map<String, String>> submit = executorService.submit(inverseCodingTask);
            if(submit != null && submit.get() != null && submit.get().size() > 0){
                singleResult.add(submit);
            }

        }

        //线程关闭(5分钟后强制关闭)
        executorService.shutdown();
        try {
            if (!executorService.awaitTermination(5, TimeUnit.MINUTES)) {
                log.info("业务处理超时5min，强制关闭");
                executorService.shutdownNow();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            executorService.shutdownNow();
        } finally {

        }

        //合并结果集合
        try {
            for (int i = 0; i < singleResult.size(); i++) {
                Map<String, String> stringStringMap = singleResult.get(i).get();
                if(stringStringMap != null){
                    result.putAll(stringStringMap);
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        log.info("返回结果长度：" + result.size());
        return result;
    }

    /**
     * 批量手动转换坐标
     */
    @Override
    public void convertLocationTest() {
        File file = new File("D:\\linkapp_project\\aep\\linkapp_second\\linkapp-api\\src\\main\\resources\\sql\\linkapp_5.0.0\\荆州油烟刷设备经纬度\\orignal_data.txt");
        List<ConvertLocationParams> parameters = new ArrayList<>();
        if (file.exists()) {
            FileInputStream fis = null;
            try {
                fis = new FileInputStream(file);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            Scanner scanner = new Scanner(new BufferedInputStream(fis), "UTF-8");
            scanner.useLocale(Locale.CHINA);
            while (scanner.hasNextLine()) {
                String line = scanner.nextLine();
                String[] tokens = line.split(",");
                String v0 = tokens[0];
                String v1 = tokens[1];
                parameters.add(new ConvertLocationParams(v0.trim() + "," + v1.trim()));
            }
        }
        Map<String, String> res = null;
        try {
            res = convertLocation(parameters);
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            log.error("error:", e);
        }
        System.out.println("转换后结果是：" + res);
    }

    @Override
    public Map<String, String> convertLocation(List<ConvertLocationParams> parameters) throws ExecutionException, InterruptedException {
        Map<String, String> result = new LinkedHashMap<>();
        if(parameters == null || parameters.isEmpty()){
            return result;
        }
        List<String> locationList = parameters.stream().map(ConvertLocationParams::getLocation).collect(Collectors.toList());

        int size = locationList.size();
        int baseNum = 40;
        /**将集合切分的段数**/
        int sunSum = GaodeUtils.getLoopCount(size, baseNum);
        int listStart,listEnd;

        //存储线程的返回值
        List<Future<Map<String, String>>> singleResult = new LinkedList<Future<Map<String, String>>>();
        ExecutorService executorService;
        ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").get();
        executorService = new ThreadPoolExecutor(50, 100,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>(4096), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());

        for (int i = 1; i <= sunSum; i++) {
            listStart = (i-1)*baseNum;
            listEnd = listStart + baseNum;
            if(i == sunSum){
                listEnd = size;
            }
            List<String> sunList = locationList.subList(listStart,listEnd);
            StringBuilder locationAppend = new StringBuilder();
            for (String location:
                    sunList) {
                locationAppend.append("|").append(location);
            }
            String reqLocation = locationAppend.toString();
            reqLocation = reqLocation.substring(1);
            //可选值：gps;mapbar;baidu;autonavi(不进行转换) api 说明：https://lbs.amap.com/api/webservice/guide/api/convert
            ConvertLocationTask convertLocationTask = new ConvertLocationTask(reqLocation, "gps", key, locationConvertUrl);
            Future<Map<String, String>> submit = executorService.submit(convertLocationTask);
            if(submit != null && submit.get() != null && submit.get().size() > 0){
                singleResult.add(submit);
            }
        }

        //线程关闭(5分钟后强制关闭)
        executorService.shutdown();
        try {
            if (!executorService.awaitTermination(5, TimeUnit.MINUTES)) {
                log.info("业务处理超时5min，强制关闭");
                executorService.shutdownNow();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            executorService.shutdownNow();
        } finally {

        }

        //合并结果集合
        try {
            for (int i = 0; i < singleResult.size(); i++) {
                Map<String, String> stringStringMap = singleResult.get(i).get();
                if(stringStringMap != null){
                    result.putAll(stringStringMap);
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        log.info("返回结果长度：" + result.size());
        return result;
    }

    @Override
    public FenceRelationResult getFenceRelation(String sid, String location, String gfids, Integer page, Integer pagesize) {
        Map<String, Object> parametersMap = new HashMap<>(20);
        parametersMap.put("location", location);
        parametersMap.put("sid", sid);
        parametersMap.put("key", key);
        parametersMap.put("gfids", gfids);
        parametersMap.put("page", page);
        parametersMap.put("pagesize", pagesize);

        String url = trackLocationUrl + HttpClientUtil.asUrlParams(parametersMap);
        HttpGet httpGet = new HttpGet(url);
        String result = HttpClientUtil.doGet(httpGet);
        log.info("坐标与围栏关系  高德api请求   url=" + url);
        log.info("坐标与围栏关系  高德api响应   result=" + result);
        FenceRelationResult fenceRelationResult = JSONObject.parseObject(result, FenceRelationResult.class);
        return fenceRelationResult;
    }

    @Override
    public FenceRelationResult getFenceRelation(String location, String gfids, Integer page, Integer pagesize) {
        //默认取配置sid
        return getFenceRelation(sid, location, gfids, page, pagesize);
    }

    @Override
    public GeoFenceApiResult addOrUpdateCircle(GeoFence geoFence) throws Exception {
        initParamGeoFence(geoFence);
        return GeoFenceUtil.addOrUpdateCircle(geoFence);
    }

    @Override
    public GeoFenceApiResult addOrUpdatePolygon(GeoFence geoFence) throws Exception {
        initParamGeoFence(geoFence);
        return GeoFenceUtil.addOrUpdatePolygon(geoFence);
    }

    @Override
    public GeoFenceApiResult delete(GeoFence geoFence) throws Exception {
        initParamGeoFence(geoFence);
        return GeoFenceUtil.delete(geoFence);
    }

    @Override
    public GeoFenceApiResult list(GeoFence geoFence) throws Exception {
        initParamGeoFence(geoFence);
        return GeoFenceUtil.list(geoFence);
    }
    /**
     * 初始化参数
     * @param geoFence
     */
    private void initParamGeoFence(GeoFence geoFence){
        geoFence.setUrl(fenceUrl);
        geoFence.setSid(sid);
        geoFence.setKey(key);
    }

    private int getLoopCount(int listSize, int baseNum){
        int count = 0;
        int num = listSize / baseNum;
        if(num == 0){
            count = 1;
        }
        else{
            int num2 = listSize % baseNum;
            if(num2 == 0){
                count = num;
            }else {
                count = num + 1;
            }
        }
        return count;
    }

}
